package com.metronoteapp;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.FloatMath;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import com.metronoteapp.database.GroupNoteDao;
import com.metronoteapp.database.NoteDao;
import com.metronoteapp.model.GroupModel;
import com.metronoteapp.model.NoteModel;
import com.metronoteapp.until.Constants;

public class CameraActivity extends Activity implements OnTouchListener {

	private static final String TAG = CameraActivity.class.getSimpleName();
	final int TAKE_PICTURE = 1;
	private Uri imageUri;
	private Context mContext;
	private Boolean mBlnCheckOk = false;
	private Button mBtnOk;
	private Button mBtnCancel;
	private TextView mTxtTitle;
	private TextView mTxtDes;
	private NoteModel mObjNoteModel;
	private NoteDao mObjNoteDao;
	private Spinner spnGroupNote;
	private List<String> choices;
	private GroupNoteDao mObjGroupDao;
	private GroupModel mObjGroupModel;
	private String txtGroup;

	// Variable for zooming image
	// These matrices will be used to move and zoom image
	public static Matrix matrix = new Matrix();
	public static Matrix savedMatrix = new Matrix();
	public static PointF start = new PointF();
	public static PointF mid = new PointF();
	public static final int NONE = 0;
	public static final int DRAG = 1;
	public static final int ZOOM = 2;
	public static int mode = NONE;
	float oldDist;

	/** Called when the activity is first created. **/
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		// Set full Screen activity
		WindowManager.LayoutParams attrs = this.getWindow().getAttributes();
		attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
		this.getWindow().setAttributes(attrs);
		setContentView(R.layout.layout_camera);
		mContext = this;
		mBtnOk = (Button) findViewById(R.id.btnSaveImage);
		mBtnCancel = (Button) findViewById(R.id.btnCancelImage);
		mTxtTitle = (TextView) findViewById(R.id.txtTitleImage);
		mTxtDes = (TextView) findViewById(R.id.txtDesImage);

		// Create folder
		File direct = new File(com.metronoteapp.until.Constants.PATH_IMAGE);
		Log.v(TAG, com.metronoteapp.until.Constants.PATH_IMAGE);
		if (!direct.exists()) {
			if (direct.mkdir()) {
				Log.v(TAG, "takePhoto() | Created folder: "
						+ com.metronoteapp.until.Constants.PATH_IMAGE);
			} else {
				Log.v(TAG, "takePhoto() | Created Failed!" + direct.getParent());
			}

		} else {
			Log.v(TAG, "takePhoto() | Folder exist");
		}

		// Call camera
		takePhoto();

		// Setting data for spinner
		setGroupDataForSpinner();
		ArrayAdapter<String> adapter = new ArrayAdapter<String>(mContext,
				android.R.layout.simple_dropdown_item_1line, choices);
		spnGroupNote = (Spinner) findViewById(R.id.spinner1);
		spnGroupNote.setAdapter(adapter);

		// Save image note
		mBtnOk.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {

				int intGroupId;
				txtGroup = (String) spnGroupNote.getItemAtPosition(spnGroupNote
						.getSelectedItemPosition());
				if (mTxtTitle.getText().toString().trim().equalsIgnoreCase("")) {
					Toast.makeText(mContext, "Error: Title is null.",
							Toast.LENGTH_SHORT).show();
				} else {

					String pathImage = imageUri.toString().substring(7,
							imageUri.toString().length());

					// Get group id
					mObjGroupDao = new GroupNoteDao(mContext);
					mObjGroupDao.openDB();
					mObjGroupModel = new GroupModel();
					mObjGroupModel.setGroupName(txtGroup);
					Cursor mCursor = mObjGroupDao
							.getGroupByName(mObjGroupModel);
					if (mCursor.moveToFirst()) {
						do {
							intGroupId = Integer.parseInt(getColumnAsString(
									mCursor, 0));
						} while (mCursor.moveToNext());
					} else {
						intGroupId = 0;
					}
					Log.v(TAG, "saveNewNote() | GroupID add : " + intGroupId);
					mObjGroupDao.closeDB();

					// Update or insert note
					Date cDate = new Date();
					String fDate = new SimpleDateFormat("yyyy-MM-dd")
							.format(cDate);
					mObjNoteDao = new NoteDao(mContext);
					mObjNoteDao.openDB();
					mObjNoteModel = new NoteModel();
					mObjNoteModel.setTitle(mTxtTitle.getText().toString()
							.trim());
					mObjNoteModel.setContent(pathImage + "|"
							+ mTxtDes.getText());
					mObjNoteModel.setGroupId(intGroupId);
					mObjNoteModel.setFlgFav(0);
					mObjNoteModel.setNoteType(Constants.TYPE_PICTURE);
					mObjNoteModel.setDateTime(fDate);
					mObjNoteDao.insertNote(mObjNoteModel);
					mObjNoteDao.closeDB();

					Intent callMainNote = new Intent(mContext,
							MainActivity.class);
					mContext.startActivity(callMainNote);
				}
			}
		});

		// Discard image not
		mBtnCancel.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub

				String pathDel = imageUri.toString().substring(7,
						imageUri.toString().length());
				if (mBlnCheckOk == true) {
					if (!pathDel.equalsIgnoreCase("")) {
						deleteImage(pathDel);
					}
				}
				Intent callMainNote = new Intent(mContext, MainActivity.class);
				mContext.startActivity(callMainNote);
			}
		});
	}

	@Override
	public boolean onKeyUp(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK) {
			onBackPressed();
			return true;
		}
		return super.onKeyUp(keyCode, event);
	}

	@Override
	public void onBackPressed() {
		String pathDel = imageUri.toString().substring(7,
				imageUri.toString().length());
		if (mBlnCheckOk == true) {
			if (!pathDel.equalsIgnoreCase("")) {
				deleteImage(pathDel);
			}
		}
	}

	/** After captured a picture then show that image **/
	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		switch (requestCode) {
		case TAKE_PICTURE:
			if (resultCode == Activity.RESULT_OK) {

				// Setting image
				Uri selectedImage = imageUri;
				final ImageView imageView = (ImageView) findViewById(R.id.IMAGE);
				Bitmap bitmap = getBitmap(selectedImage);
				bitmap = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth(),
						bitmap.getHeight(), true);

				// Setting rotate following rotation of image
				Matrix matrix = new Matrix();
				matrix.postRotate(90);
				Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
						bitmap.getWidth(), bitmap.getHeight(), matrix, true);

				Bitmap roundedBitmap = this.roundCorner(rotatedBitmap, 20);

				// Set image into imageview
				imageView.setImageBitmap(roundedBitmap);

				final Animation animBounce = AnimationUtils.loadAnimation(this,
						R.anim.bounce);
				imageView.startAnimation(animBounce);
				mBlnCheckOk = true;
			}
		}
	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		// TODO Auto-generated method stub
		ImageView view = (ImageView) v;

		switch (event.getAction() & MotionEvent.ACTION_MASK) {

		case MotionEvent.ACTION_DOWN:

			savedMatrix.set(matrix);
			start.set(event.getX(), event.getY());
			Log.d(TAG, "mode=DRAG");
			mode = DRAG;
			break;

		case MotionEvent.ACTION_POINTER_DOWN:

			oldDist = spacing(event);
			Log.d(TAG, "oldDist=" + oldDist);
			if (oldDist > 10f) {

				savedMatrix.set(matrix);
				midPoint(mid, event);
				mode = ZOOM;
				Log.d(TAG, "mode=ZOOM");
			}
			break;

		case MotionEvent.ACTION_MOVE:

			if (mode == DRAG) {

				matrix.set(savedMatrix);
				matrix.postTranslate(event.getX() - start.x, event.getY()
						- start.y);
			} else if (mode == ZOOM) {

				float newDist = spacing(event);
				Log.d(TAG, "newDist=" + newDist);
				if (newDist > 10f) {

					matrix.set(savedMatrix);
					float scale = newDist / oldDist;
					matrix.postScale(scale, scale, mid.x, mid.y);
				}
			}
			break;

		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_POINTER_UP:

			mode = NONE;
			Log.d(TAG, "mode=NONE");
			break;
		}

		// Perform the transformation
		view.setImageMatrix(matrix);
		return true;
	}

	private float spacing(MotionEvent event) {
		float x = event.getX(0) - event.getX(1);
		float y = event.getY(0) - event.getY(1);
		return FloatMath.sqrt(x * x + y * y);
	}

	private void midPoint(PointF point, MotionEvent event) {

		float x = event.getX(0) + event.getX(1);
		float y = event.getY(0) + event.getY(1);
		point.set(x / 2, y / 2);
	}

	/** Call camera **/
	public void takePhoto() {
		Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
		Date cDate = new Date();
		String fDateImage = new SimpleDateFormat("yyyyMMdd_HHmmss")
				.format(cDate);
		File photo = new File(Constants.PATH_IMAGE, fDateImage + "Pic.jpg");
		intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
		imageUri = Uri.fromFile(photo);
		startActivityForResult(intent, TAKE_PICTURE);
	}

	/** decodes image and scales it to reduce memory consumption **/
	private Bitmap getBitmap(Uri path) {

		Uri uri = path;
		InputStream in = null;
		try {
			final int IMAGE_MAX_SIZE = 1500000; // 1.5MP
			ContentResolver mContentResolver = getContentResolver();
			in = mContentResolver.openInputStream(uri);

			// Decode image size
			BitmapFactory.Options o = new BitmapFactory.Options();
			o.inJustDecodeBounds = true;
			BitmapFactory.decodeStream(in, null, o);
			in.close();

			int scale = 1;
			while ((o.outWidth * o.outHeight) * (1 / Math.pow(scale, 2)) > IMAGE_MAX_SIZE) {
				scale++;
			}
			Log.d(TAG, "scale = " + scale + ", orig-width: " + o.outWidth
					+ ", orig-height: " + o.outHeight);

			Bitmap b = null;
			in = mContentResolver.openInputStream(uri);
			if (scale > 1) {
				scale--;
				// scale to max possible inSampleSize that still yields an image
				// larger than target
				o = new BitmapFactory.Options();
				o.inSampleSize = scale;
				b = BitmapFactory.decodeStream(in, null, o);

				// resize to desired dimensions
				int height = b.getHeight();
				int width = b.getWidth();
				Log.d(TAG, "1th scale operation dimenions - width: " + width
						+ ",height: " + height);

				double y = Math.sqrt(IMAGE_MAX_SIZE
						/ (((double) width) / height));
				double x = (y / height) * width;

				Bitmap scaledBitmap = Bitmap.createScaledBitmap(b, (int) x,
						(int) y, true);
				b.recycle();
				b = scaledBitmap;

				System.gc();
			} else {
				b = BitmapFactory.decodeStream(in);
			}
			in.close();

			Log.d(TAG, "bitmap size - width: " + b.getWidth() + ", height: "
					+ b.getHeight());
			return b;
		} catch (IOException e) {
			Log.e(TAG, e.getMessage(), e);
			return null;
		}
	}

	/** Get ratation of image **/
	public int getOrientation(Uri selectedImage) {
		int orientation = 0;
		final String[] projection = new String[] { MediaStore.Images.Media.ORIENTATION };
		final Cursor cursor = mContext.getContentResolver().query(
				selectedImage, projection, null, null, null);
		if (cursor != null) {
			final int orientationColumnIndex = cursor
					.getColumnIndex(MediaStore.Images.Media.ORIENTATION);
			if (cursor.moveToFirst()) {
				orientation = cursor.isNull(orientationColumnIndex) ? 0
						: cursor.getInt(orientationColumnIndex);
			}
			cursor.close();
		}
		return orientation;
	}

	/** Android image rounded corners **/
	public static Bitmap roundCorner(Bitmap src, float round) {

		// image size
		int width = src.getWidth();
		int height = src.getHeight();

		// create bitmap output
		Bitmap result = Bitmap.createBitmap(width, height, Config.ARGB_8888);

		// set canvas for painting
		Canvas canvas = new Canvas(result);
		canvas.drawARGB(0, 0, 0, 0);

		// config paint
		final Paint paint = new Paint();
		paint.setAntiAlias(true);
		paint.setColor(Color.BLACK);

		// config rectangle for embedding
		final Rect rect = new Rect(0, 0, width, height);
		final RectF rectF = new RectF(rect);

		// draw rect to canvas
		canvas.drawRoundRect(rectF, round, round, paint);

		// create Xfer mode
		paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));

		// draw source image to canvas
		canvas.drawBitmap(src, rect, rect, paint);

		// return final image
		return result;
	}

	/** Delete an image from sdcard **/
	public void deleteImage(String _path) {
		File direct = new File(_path);
		Log.v(TAG, "Path delete: " + _path);
		if (direct.exists()) {
			direct.delete();
		} else {
			Log.v(TAG, "Error deleting image: Path not exists : " + _path);
		}
	}

	/** Setting data for spinner group **/
	public void setGroupDataForSpinner() {
		mObjGroupDao = new GroupNoteDao(mContext);
		choices = new ArrayList<String>();
		mObjGroupDao.openDB();
		Cursor mCursor = mObjGroupDao.getAllRecord();
		Log.v(TAG, "setGroupDataForSpinner() | " + mCursor.getCount());
		if (mCursor.moveToFirst()) {
			do {
				Log.v(TAG, "setGroupDataForSpinner() | Valued: "
						+ getColumnAsString(mCursor, 1));
				choices.add(getColumnAsString(mCursor, 1));
			} while (mCursor.moveToNext());
		}
		mObjGroupDao.closeDB();
	}

	/** This function parse cursor **/
	private static String getColumnAsString(Cursor cursor, int index) {
		return cursor.getString(index).trim();
	}
}
